package yxgf.oem.oemquotemgt.mservice.service.impl;

import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.nacos.common.utils.StringUtils;
import kd.bos.coderule.api.CodeRuleInfo;
import kd.bos.dataentity.OperateOption;
import kd.bos.dataentity.entity.CloneUtils;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.metadata.IDataEntityType;
import kd.bos.dataentity.metadata.dynamicobject.DynamicObjectType;
import kd.bos.entity.operate.result.OperationResult;
import kd.bos.openapi.common.result.CustomApiResult;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.QueryServiceHelper;
import kd.bos.servicehelper.coderule.CodeRuleServiceHelper;
import kd.bos.servicehelper.operation.OperationServiceHelper;
import org.springframework.stereotype.Service;
import yxgf.oem.oemquotemgt.commons.dto.*;
import yxgf.oem.oemquotemgt.commons.enums.ContractQuoteModeEnum;
import yxgf.oem.oemquotemgt.commons.enums.QuoteModeEnum;
import yxgf.oem.oemquotemgt.commons.enums.QuoteTypeEnum;
import yxgf.oem.oemquotemgt.commons.utils.DateUtils;
import yxgf.oem.oemquotemgt.mservice.service.IContractAppointService;

import java.time.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @description： 合同约定服务服务
 * @version: v1.0
 * @author: Junit
 * @date: 2025/5/14
 */
@Service
public class ContractAppointServiceImpl implements IContractAppointService {
    private static final Log logger = LogFactory.getLog(ContractAppointServiceImpl.class);

    /**
     * 日志消息
     */
    public static final String LOG_PREFIX = "合同约定单定时生成定价单定时任务-";

    @Override
    public CustomApiResult<Boolean> genQuoteBill() {
        LocalDate today = LocalDate.now();
        int dayOfMonth = today.getDayOfMonth();
        int currYear = today.getYear();
        int currMonth = today.getMonthValue();

        /**
         * 一、获取已审核合同信息
         */
        QFilter qFilter1 = new QFilter("billstatus", QCP.equals, "C");
        QFilter qFilter2 = new QFilter("yxgf_start_date", QCP.less_equals, today);
        QFilter qFilter3 = new QFilter("yxgf_end_date", QCP.large_equals, today);
        // QFilter qFilter4 = new QFilter("yxgf_entryentity_qperiod.yxgf_qdate", QCP.equals, dayOfMonth);
        QFilter filter = qFilter1.and(qFilter2).and(qFilter3);

        DynamicObjectCollection contractBill = QueryServiceHelper.query("yxgf_contract_bill",
                "id,billno," +
                        "yxgf_saleorg as saleorg," +
                        "yxgf_customer as customer," +
                        "yxgf_quote_mode as quote_mode," +
                        "yxgf_advanced_days as advanced_days," +
                        "yxgf_principal," +
                        "yxgf_order_addr," +
                        "yxgf_stock_addr," +
                        "yxgf_reserved_addr," +
                        "yxgf_real_pro_org as real_pro_org," +
                        "yxgf_start_date," +
                        "yxgf_end_date," +
                        "yxgf_base_day," +
                        "yxgf_quote_days," +
                        "yxgf_range," +
                        "yxgf_base_x," +
                        "yxgf_entryentity_qperiod.yxgf_qdate as quote_date," +
                        "yxgf_show_formula as show_formula," +
                        "yxgf_show_quote_price  as quote_price," +
                        "yxgf_show_base_cost  as base_cost," +
                        "yxgf_show_last_price  as last_price",
                filter.toArray());

        List<ContractBaseInfoDto> contractOriList = new ArrayList<>();
        for (DynamicObject dyn : contractBill) {
            // 1、基本信息
            ContractBaseInfoDto baseInfoDto = new ContractBaseInfoDto();
            // ID
            baseInfoDto.setId(dyn.getLong("id"));
            // 编号
            baseInfoDto.setBillNo(dyn.getString("billno"));
            // 客户
            baseInfoDto.setCusId(dyn.getLong("customer"));

            // 2、提前生成定价单天数
            baseInfoDto.setAdvancedDay(dyn.getInt("advanced_days"));

            // 3、报价日
            List<Integer> qDays = new ArrayList<>();
            qDays.add(dyn.getInt("quote_date"));
            baseInfoDto.setQuoteDays(qDays);
            // 合同日期
            baseInfoDto.setContractStarDay(dyn.getDate("yxgf_start_date"));
            // 合同结束日期
            baseInfoDto.setContractEndDay(dyn.getDate("yxgf_end_date"));

            // 4、订单地址
            baseInfoDto.setOrderAddrId(dyn.getLong("yxgf_order_addr"));
            // 库存地址
            baseInfoDto.setStockAddrId(dyn.getLong("yxgf_stock_addr"));
            // 预留空间
            baseInfoDto.setReservedAddrId(dyn.getLong("yxgf_reserved_addr"));
            // 实际产品地址
            baseInfoDto.setRealProAddrId(dyn.getLong("real_pro_org"));

            // 5、隐藏项设置
            baseInfoDto.setShowFormula(dyn.getInt("show_formula"));
            baseInfoDto.setShowPricing(dyn.getInt("quote_price"));
            baseInfoDto.setShowBaseCost(dyn.getInt("base_cost"));
            baseInfoDto.setShowLastPrice(dyn.getInt("last_price"));

            // 6、获取产品
            List<ContractProductDto> productDtoList = new ArrayList<>();
            Long billId = dyn.getLong("id");
            DynamicObject contractProBill = BusinessDataServiceHelper.loadSingle(billId, "yxgf_contract_bill");
            DynamicObjectCollection proEntity = contractProBill.getDynamicObjectCollection("yxgf_entryentity_pro");
            for (DynamicObject pro : proEntity) {
                ContractProductDto tem = new ContractProductDto();
                tem.setProId(pro.getLong("yxgf_pro_code"));
                tem.setMount(pro.getBigDecimal("yxgf_pro_amount"));
            }
            baseInfoDto.setProductDtoList(productDtoList);

            /*
             * 7、报价模式
             * -原料价格：产品，隐藏【报价规则】、【基数计算方式】、【汇易网价格明细】
             * -汇易网价格：产品，【报价规则】、【基数计算方式】、【汇易网价格明细】
             */
            baseInfoDto.setQuoteMode(dyn.getString("quote_mode"));
            if ((StringUtils.equals(baseInfoDto.getQuoteMode(), QuoteModeEnum.QUOTE_TYPE_HYW_RELEVANCE.getCode()) ||
                    (StringUtils.equals(baseInfoDto.getQuoteMode(), QuoteModeEnum.QUOTE_TYPE_HYW_SAME_FREQUENCY.getCode()))
            )) {
                // 报价规则
                ContractQuoteRuleDto quoteRuleDto = new ContractQuoteRuleDto();
                quoteRuleDto.setBaseXDays(dyn.getDate("yxgf_base_day"));
                quoteRuleDto.setQuoteDays(dyn.getInt("yxgf_quote_days"));
                quoteRuleDto.setBaseX(dyn.getBigDecimal("yxgf_base_x"));
                // 波动范围
                quoteRuleDto.setRange(dyn.getBigDecimal("yxgf_range"));
                baseInfoDto.setContractQuoteRuleDto(quoteRuleDto);

                // 基数计算方式1
//                // List<ContractBaseWayDto> baseWayList = new ArrayList<>();
//                DynamicObjectCollection bwEntity = contractProBill.getDynamicObjectCollection("yxgf_base_compute");
//                for (DynamicObject bw : bwEntity) {
//                    ContractBaseWayDto basex = new ContractBaseWayDto();
//                    // 物料信息
//                    DynamicObject matObj = (DynamicObject) bw.get("yxgf_material_code");
//                    QFilter qfilter = new QFilter("number", QCP.equals, matObj.getString("number"));
//                    DynamicObject dynObj = QueryServiceHelper.queryOne("bd_material", "id", qfilter.toArray());
//                    long matId = dynObj.getLong("id");
//                    basex.setMatId(matId);   // 1971833947243732992
//                    basex.setSourceAddr(bw.getString("yxgf_addr"));
//                    basex.setSourceChanId(bw.getLong("yxgf_source.id"));
//                    basex.setWeight(bw.getBigDecimal("yxgf_weight"));
//                    basex.setAvgPrice(bw.getBigDecimal("yxgf_avg_price"));
//
//                    // 3、汇易网价格
//                    DynamicObjectCollection hywEntity = bw.getDynamicObjectCollection("yxgf_subentryentity_hyw");
//                    List<ContractHywPriceDto> hywPriceList = new ArrayList<>();
//                    for (DynamicObject hyw : hywEntity) {
//                        ContractHywPriceDto hywPriceDto = new ContractHywPriceDto();
//                        hywPriceDto.setMatId(matId);
//                        hywPriceDto.setDate(hyw.getDate("yxgf_date"));
//                        hywPriceDto.setHywPrice(hyw.getBigDecimal("yxgf_hyw_price"));
//                        hywPriceList.add(hywPriceDto);
//                    }
//                    basex.setHywPriceList(hywPriceList);
//                    baseWayList.add(basex);
//                }
//                baseInfoDto.setBaseWayDtoDynObj(baseWayList);

                // 基数计算方式2
                DynamicObjectCollection bwEntity = contractProBill.getDynamicObjectCollection("yxgf_base_compute");
                baseInfoDto.setBaseWayDtoDynObj(bwEntity);
            }
            contractOriList.add(baseInfoDto);
        }

        /**
         * 二、获取报价合同
         */
        List<ContractBaseInfoDto> list = contractOriList.stream()
                .filter(distinctByKey(ContractBaseInfoDto::getBillNo))
                .collect(Collectors.toList());

        /**
         * 三、获取报价日合同
         */
        List<ContractBaseInfoDto> dataList = new ArrayList<>();
        for (ContractBaseInfoDto tem : list) {
            // 查找相同合同
            List<ContractBaseInfoDto> sameConBill = findContractsByBillNo(contractOriList, tem.getBillNo());
            for (ContractBaseInfoDto sameCon : sameConBill) {
                // 1、预测日
                int advancedDays = sameCon.getAdvancedDay();
                if (advancedDays < 1 || advancedDays > 31) {
                    logger.info(LOG_PREFIX + "生成报价单失败，获取提前生成定价单天数无效，值为:" + advancedDays);
                    continue;
                }

                // 2、生成完整报价日，确保报价日期存在
                if (sameCon.getQuoteDays() == null || sameCon.getQuoteDays().get(0) < 0 || sameCon.getQuoteDays().get(0) > 31) {
                    logger.info(LOG_PREFIX + "生成报价单失败，当前报价日期无效");
                    continue;
                }
                LocalDate quoteDay;
                try {
                    quoteDay = LocalDate.of(currYear, currMonth, sameCon.getQuoteDays().get(0));
                } catch (DateTimeException e) {
                    continue;
                }

                // 3、生成报价日期
                LocalDate quoteDate = quoteDay.minusDays(advancedDays);

                // 4、判断是否是报价当天，生成定价单
                boolean result = DateUtils.isBetween(quoteDate,
                        DateUtils.convertLocalDate(sameCon.getContractStarDay()),
                        DateUtils.convertLocalDate(sameCon.getContractEndDay()));

                // 调度任务日期满足生成定价单日期且在合同有效期内
                if (result && today.equals(quoteDate)) {
                    dataList.add(sameCon);
                }
            }
        }

        // 批量生成定价单
        genQBillEntity(dataList, today);
        return CustomApiResult.success(true);
    }


    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    /**
     * 查找日期
     *
     * @param conBills
     * @param billNo
     * @return
     */
    public static List<ContractBaseInfoDto> findContractsByBillNo(List<ContractBaseInfoDto> conBills, String billNo) {
        return conBills.stream()
                .filter(order -> order.getBillNo().equals(billNo))
                .collect(Collectors.toList());
    }

    /**
     * 批量生成定价单
     *
     * @param contractInfos
     * @param today
     */
    private void genQBillEntity(List<ContractBaseInfoDto> contractInfos, LocalDate today) {
        ArrayList<DynamicObject> dynObjects = new ArrayList<>();
        for (ContractBaseInfoDto baseInfoDto : contractInfos) {
            // 获取单据单信息
            DynamicObject quoteBill = getQuoteBillByNo(baseInfoDto.getBillNo());

            // 合同基本信息
            // boolean existBill = quoteBill == null ? false : true;
            DynamicObject contractEntity = genContractInfo(baseInfoDto, quoteBill, today);

            // 合同产品
            dynObjects.add(contractEntity);
        }

        if (contractInfos.size() > 0) {
            DynamicObject[] dynObjArr = dynObjects.stream().toArray(DynamicObject[]::new);
            OperationServiceHelper.executeOperate("save", "yxgf_recipe_pricing", dynObjArr, OperateOption.create());
        }
        // logger.info(LOG_PREFIX + "生成定价单完成");
    }


    /**
     * 根据合同相关信息封装定价单数据
     *
     * @param baseInfoDto
     * @param sourceBill
     * @param today
     * @return
     */
    private DynamicObject genContractInfo(ContractBaseInfoDto baseInfoDto, DynamicObject sourceBill, LocalDate today) {
        DynamicObject contractEntity = BusinessDataServiceHelper.newDynamicObject("yxgf_recipe_pricing");
        IDataEntityType dataType = contractEntity.getDataEntityType();
        String ruleName = dataType.getName();
        CodeRuleInfo codeRule = CodeRuleServiceHelper.getCodeRule(ruleName, contractEntity, null);

        /**
         * 基本信息
         */
        String billNo = CodeRuleServiceHelper.getNumber(codeRule, contractEntity);
        // 单据编号
        contractEntity.set("billno", billNo);
        // 已经存在定价单
        if (sourceBill != null) {
            CloneUtils cloneUtils = new CloneUtils(false, true);
            DynamicObject newEntity = (DynamicObject) cloneUtils.clone(sourceBill);
            contractEntity = newEntity;

            DynamicObject dynamicObject = BusinessDataServiceHelper.loadSingle(sourceBill.getLong("id"),
                    "yxgf_recipe_pricing");
            // 获取产品
            DynamicObject proObj = dynamicObject.getDynamicObject("yxgf_entryentity");
            // 获取配方信息
            DynamicObject formulaObj = dynamicObject.getDynamicObject("yxgf_subentryentity1");
            // 营养占比
            DynamicObject nutItemObj = dynamicObject.getDynamicObject("yxgf_subentryentity11");

        } else {
            // 设置合同编号
            contractEntity.set("yxgf_contractld", baseInfoDto.getId());

            // 产品 【yxgf_entryentity_pro/yxgf_pro_code、yxgf_pro_amount】
            DynamicObjectCollection pro = contractEntity.getDynamicObjectCollection("yxgf_entryentity");
            genProInfo(pro, baseInfoDto.getProductDtoList());
        }
        // 单据状态-暂存
        contractEntity.set("billstatus", "A");
        // 客户ID
        contractEntity.set("yxgf_customer", baseInfoDto.getCusId());
        // 报价类型-合同报价/售前
        contractEntity.set("yxgf_combofield", QuoteTypeEnum.QUOTE_MODE_CON_SALE.getCode());
        // 报价模式
        contractEntity.set("yxgf_bjlx", baseInfoDto.getQuoteMode());


        /**
         * 合同约定
         */
        // 合同编号
        contractEntity.set("yxgf_contractld", baseInfoDto.getBillNo());
        // 开始日期
        contractEntity.set("yxgf_start_qdatetime", baseInfoDto.getContractStarDay());
        // 结束日期
        contractEntity.set("yxgf_qend_datetime", baseInfoDto.getContractEndDay());
        // 负责人
        contractEntity.set("yxgf_principal", baseInfoDto.getPrincipalId());

        /**
         * 设置隐藏项
         */
        contractEntity.set("yxgf_radiooptgroupfield", baseInfoDto.getShowFormula());
        contractEntity.set("yxgf_radiooptgroupfield1", baseInfoDto.getShowPricing());
        contractEntity.set("yxgf_radiooptgroupfield2", baseInfoDto.getShowBaseCost());
        contractEntity.set("yxgf_show_lastprice", baseInfoDto.getShowLastPrice());

        /**
         * 报价模式：【原料、汇易联动、同频】
         */
        if ((StringUtils.equals(baseInfoDto.getQuoteMode(), QuoteModeEnum.QUOTE_TYPE_HYW_RELEVANCE.getCode()) ||
                (StringUtils.equals(baseInfoDto.getQuoteMode(), QuoteModeEnum.QUOTE_TYPE_HYW_SAME_FREQUENCY.getCode()))
        )) {
            /*
             * 1、报价规则
             */
            ContractQuoteRuleDto conRule = baseInfoDto.getContractQuoteRuleDto();
            ZonedDateTime zonedDateTime = today.atStartOfDay(ZoneId.systemDefault());
            Date date = Date.from(zonedDateTime.toInstant());
            // 合同基数计算日期
            contractEntity.set("yxgf_contrat_base_date", date);
            // 合同基数计算天数
            contractEntity.set("yxgf_base_days", conRule.getBaseXDays());
            // 合同基数
            contractEntity.set("yxgf_amountfield3", conRule.getBaseX());
            // 同频调整-波动范围
            if (StringUtils.equals(baseInfoDto.getQuoteMode(), QuoteModeEnum.QUOTE_TYPE_HYW_SAME_FREQUENCY.getCode())) {
                contractEntity.set("yxgf_range", conRule.getRange());
            }

            /*
             * 2、基数计算方式
             */
            List<ContractBaseWayDto> wayList = new ArrayList<>();
            DynamicObjectCollection baseXCollect = baseInfoDto.getBaseWayDtoDynObj();
            for (DynamicObject dynamicObj : baseXCollect) {
                DynamicObject chanel = dynamicObj.getDynamicObject("yxgf_material_code");
                // 获取渠道信息
                ContractBaseWayDto wayDto = new ContractBaseWayDto();
                wayDto.setMatId(chanel.getLong("id"));
                //  wayDto.setSourceAddr(dynamicObj.getString("yxgf_addr"));
                wayDto.setWeight(dynamicObj.getBigDecimal("yxgf_weight"));
                wayList.add(wayDto);
            }
            DynamicObjectCollection baseXDynObjColl = contractEntity.getDynamicObjectCollection("base_compute");
            genBaseXInfo(baseXDynObjColl, wayList);
        }
        return contractEntity;
    }

    /**
     * 获取历史定价单相关信息
     *
     * @param contractNo
     * @return
     */
    private DynamicObject getQuoteBillByNo(String contractNo) {
        QFilter qFilter1 = new QFilter("billno", QCP.equals, contractNo);
        QFilter qFilter2 = new QFilter("billstatus", QCP.equals, "C");
        QFilter filter = qFilter1.and(qFilter2);
        DynamicObjectCollection comObjCollection = QueryServiceHelper.query("yxgf_recipe_pricing",
                "id," +
                        "billno," +
                        "yxgf_combofield," +
                        "yxgf_bjlx," +
                        "yxgf_start_qdatetime," +
                        "yxgf_qend_datetime," +
                        "createtime",
                filter.toArray(), "createtime desc");
        if (!comObjCollection.isEmpty()) {
            return comObjCollection.get(0);
        }
        return null;
    }

    /**
     * 生成产品
     *
     * @param dynObjCollect
     * @param productDtoList
     */
    private void genProInfo(DynamicObjectCollection dynObjCollect, List<ContractProductDto> productDtoList) {
        IntStream.range(0, productDtoList.size())
                .mapToObj(index -> genProObject(productDtoList.get(index), dynObjCollect.getDynamicObjectType()))
                .forEach(dynObjCollect::add);
    }

    private DynamicObject genProObject(ContractProductDto proDto, DynamicObjectType type) {
        DynamicObject detail = new DynamicObject(type);
        // otc产品编码
        detail.set("yxgf_basedatafield2", proDto.getProId());
        // 金额
        detail.set("yxgf_pro_amount", proDto.getMount());
        return detail;
    }


    /**
     * 生成基数计算方式
     *
     * @param dynObjCollect
     * @param wayList
     */
    private void genBaseXInfo(DynamicObjectCollection dynObjCollect, List<ContractBaseWayDto> wayList) {
        IntStream.range(0, wayList.size())
                .mapToObj(index -> genWayObject(wayList.get(index),
                        dynObjCollect.getDynamicObjectType(),
                        wayList.get(index).getHywPriceList()))
                .forEach(dynObjCollect::add);
    }

    private DynamicObject genWayObject(ContractBaseWayDto proDto, DynamicObjectType type, List<ContractHywPriceDto> hywPriceList) {
        DynamicObject baseXObj = new DynamicObject(type);
        // 编码
        baseXObj.set("yxgf_material_code", proDto.getMatId());
        // 产地
        baseXObj.set("yxgf_addr", proDto.getSourceAddr());
        // 权值
        baseXObj.set("yxgf_weight", proDto.getWeight());
        // 均价
        baseXObj.set("yxgf_avg_price", proDto.getAvgPrice());
        // 汇易网价格明细
        // DynamicObjectCollection hywPriceDyn = baseXObj.getDynamicObjectCollection("yxgf_subentryentity");
        // gentHywPriceInfo(hywPriceDyn, hywPriceList);
        return baseXObj;
    }


    /**
     * 汇易网价格明细
     *
     * @param dynObjCollect
     * @param hywPriceList
     */
    private void gentHywPriceInfo(DynamicObjectCollection dynObjCollect, List<ContractHywPriceDto> hywPriceList) {
        IntStream.range(0, hywPriceList.size())
                .mapToObj(index -> genHywData(hywPriceList.get(index), dynObjCollect.getDynamicObjectType()))
                .forEach(dynObjCollect::add);
    }

    private DynamicObject genHywData(ContractHywPriceDto hywDto, DynamicObjectType type) {
        DynamicObject hywObj = new DynamicObject(type);
        // 原料编码
        hywObj.set("yxgf_mat_code", hywDto.getMatId());
        // 日期
        hywObj.set("yxgf_date", hywDto.getDate());
        // 渠道价格
        hywObj.set("yxgf_hyw_price", hywDto.getDate());
        return hywObj;
    }
}
